<?php
class TemplateCodeGenerator extends ProxyCodeGenerator {

	const MAIN_SCOPE = 1;
	const MACRO_SCOPE = 2;
	
	private $resource;

	private $mainGenerator = null;
	private $macroGenerator = null;
	private $scope;
	private $macros;
	
	public function __construct(Resource $resource) {
		
		$this->resource = $resource;

		$this->scope = self::MAIN_SCOPE;
		$this->macros = array();
		$this->mainGenerator = $this->createGenerator(self::MAIN_SCOPE);
	}
	
	private function createGenerator($scope) 
	{
		$options = new CodeGeneratorOptions();
		$options->indentLevel = ($scope == self::MAIN_SCOPE) ? 2 : 1;
		
		return new BufferedCodeGenerator(new CodeGenerator($options));
	}
	
	public function startMacro($macroName) {
		//$this->appendCustomCode("\$context->registerMacro('__TEMPLATEID__', '$macroName');");
		$this->appendCustomCode("\$context->registerMacro(\$this, '$macroName');");
		$this->macroGenerator = $this->createGenerator(self::MACRO_SCOPE);
		$this->scope = self::MACRO_SCOPE;
	}
	
	public function endMacro() {
		$this->macros[] = $this->macroGenerator;
		$this->scope = self::MAIN_SCOPE;
	}
	
	public function output() {
		
		$this->generator()->flush();
		
		// skeleton
		$skeleton = "<?php\n";
		$skeleton .= "\$GLOBALS['gery.template.className'] = '__TEMPLATEID__';\n\n";
		$skeleton .= "final class __TEMPLATEID__ extends TemplateBase {\n\n";
		$skeleton .= "	public static function getResourceName() {\n";
		$skeleton .= "		return '" . $this->resource->getName() . "';\n";
		$skeleton .= "	}\n\n";
		$skeleton .= "	// main function\n";
		$skeleton .= "	public function main(IGeryContext \$outerContext) {\n";
		$skeleton .= "		\$context = new GeryTemplateContext(\$outerContext, \$this->getResourceName());\n";
		$skeleton .= "		\$output = '';\n";
		$skeleton .= "%s\n";
		$skeleton .= "		return \$output;\n";
		$skeleton .= "	}\n\n";
		$skeleton .= "	// macros\n";
		$skeleton .= "%s\n";
		$skeleton .= "	public function getLastModified() {\n";
		$skeleton .= "		return " . $this->resource->getLastModified() . ";\n";
		$skeleton .= "	}\n";
		$skeleton .= "}\n";
		$skeleton .= "?>";
		
		$macroCode = '';
		
		foreach ($this->macros as $macroGenerator) {
			$macroCode .= $macroGenerator->output() . "\n\n";
		}
		
		return sprintf($skeleton, parent::output(), $macroCode);
	}
	
	public function generator() {
		return ($this->scope == self::MACRO_SCOPE)
			? $this->macroGenerator
			: $this->mainGenerator;
	}
	
	
	//
	// Some static helper functions
	//
	public static function createModifiers($modifiersNodes, $compileEngine) {
		return var_export(self::getModifiersArray($modifiersNodes, $compileEngine), true);
	}
	
	private static function getModifiersArray($modifiersNodes, $compileEngine) {
		$modifiers = array();
		
		foreach ($modifiersNodes as $modifierNode) {
			$modifier = array('name' => $modifierNode->name, 'parameters' => array());
			
			if ($modifierNode->parameters != null)
				foreach ($modifierNode->parameters as $parameter) 
			{
				$compiler = new ExpressionVisitor($compileEngine);
				$parameter->accept($compiler);
				$modifier['parameters'][] = $compiler->getOutput();
			}
			
			$modifiers[] = $modifier;
		}
		
		
		return $modifiers;
	}
	
	public static function createReference(IASTNode $node, $compileEngine) {
		
		$reference = array(
			'name' => $node->name
			,'silent' => $node->silent
			,'smurk' => $node->smurk
			,'modifiers' => self::getModifiersArray($node->modifiers, $compileEngine)
		);
		
		return var_export($reference, true);
	}
}
?>